/*
 * @Author: your name
 * @Date: 2020-04-03 11:07:37
 * @LastEditTime: 2020-04-04 12:10:07
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \W+compiler-CMake\include\SemanticAnalyzer.h
 */
#ifndef SEMANTICANALYZER_H_
#define SEMANTICANALYZER_H_
#include "../include/SyntacticAnalyzer.h"

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <stack>
#include <vector>

using namespace std;

/*语义分析 主要完成 上下文有关性质的审查, 进行类型审查 这里做一个比较简单的示例
包括：
- 对 + - * / 的识别
- 对变量标记、赋值等
实现 1.变量未定义却赋值 2.变量已定义重复定义 3.变量赋值是否正确
- 输出四元组  (op,arg1,arg2,result)
*/
//可以再补充
enum identType {
    type_int = 0,
    type_string,
};

// type 包括 基本类型、结构体、指针类型（数组）
struct IdentNode
{
    string newId;     //新的变量名
    string sourceId;  //源程序中的变量名

    int identType;
};

//四元组 结构体
struct Quad
{
    string op;      //操作符
    string arg1;    //参数1
    string arg2;    //参数2
    string result;  //结果
};

class LrS {
  public:
    /**
     * @description: 添加Item
     * @param {type}
     * @return:
     */
    void addItem(string s);

    /**
     * @description: 从文件中读取 到 输入栈 并读取TOKEN.txt到行数栈
     * @param {type}
     * @return:
     */
    void getInputStack(string input);

    /**
     * @description: 展示 输入栈
     * @param {type}
     * @return:
     */
    void showInputStack();

    /**
     * @description: 展示状态栈
     * @param {type}
     * @return:
     */
    void showStateStack();

    /**
     * @description: 展示分析栈
     * @param {type}
     * @return:
     */
    void showAnalyzeStack();

    /**
     * @description: 1.求得 FIRST 集
     * @param {type}
     * @return:
     */
    set<char> getFirst(string& str);

    /**
     * @description: 2.计算项目集 I 的 e-closure集
     * @param {type}
     * @return:
     */
    Item eclosure(Item I);

    /**
     * @description: 3.计算项目集 I 经过 char X后的项目集
     * @param {type}
     * @return: eclosure(J)
     */
    Item Go(Item I, char X);

    /**
     * @description: 4.根据 初始 Item 求项目集 的 DFA
     * @param {type}
     * @return:
     */
    void itemDFA();

    /**
     * @description:5.构建 ACTION GOTO 表
     * @param {type}
     * @return:
     */
    void getAG();

    /**
     * @description: 6.语法分析的分析过程
     * @param {type}
     * @return:
     */
    void parser();

    /**
     * @description: 7.错误分析
     * @param {type}
     * @return:
     */
    void getError();

    /**
     * @description: 添加产生式
     * @param {type}
     * @return:
     */
    void addProduction(string& str);

    /**
     * @description: 展示分析过程
     * @param {type}
     * @return:
     */
    void show();

    /**
     * @description: LR运行
     * @param {type}
     * @return:
     */
    void run();

    /**
     * @description: 展示 FIRST ACTION GOTO
     * @param {type}
     * @return:
     */
    void showAFG();

  public:
    /**
     * @description: 展示 ident表
     * @param {type}
     * @return:
     */
    void showIdent();
    /**
     * @description:输出 四元组
     * @param {type}
     * @return:
     */
    void showQuad();
    /**
     * @description:语义分析
     * @param {type}
     * @return:
     */
    void parser_S();
    /**
     * @description: 是否 已存在变量
     * @param {type}
     * @return:
     */
    bool isfindIdent(string name);

    /**
     * @description: 根据 sourceId 找到变量表中的 newId
     * @param {type}
     * @return:
     */
    string findIdentbyName(string name);

    /**
     * @description: 返回一个新的变量名
     * @param {type}
     * @return:
     */
    string newIdent();

  private:
    Item         G;        //文法G 初始的文法 列表
    vector<Item> program;  //项目集规范组

    //各种栈
    vector<char> inputStack;    //输入栈
    vector<int>  stateStack;    //状态栈
    vector<char> analyzeStack;  //分析栈
    vector<int>  lineStack;     //行数栈

    // FIRST集 用于中间生成
    map<char, set<char>> FIRST;

    // ACTION表 int + char -> char + int
    map<pair<int, char>, pair<actionState, int>> ACTION;
    // GOTO表 int + char -> int
    map<pair<int, char>, int> GOTO;

  private:
    map<int, vector<string>> inputToken_ALL;
    vector<Quad>             quad_ALL;
    vector<IdentNode>        ident_ALL;
    vector<char>             inputStack_S;  //输入栈
    vector<int>              lineStack_S;   //行数栈
};

/**
 * @description: 打开文件
 * @param {type}
 * @return:
 */
void LfileOpen_S();

/**
 * @description: 关闭文件
 * @param {type}
 * @return:
 */
void LfileClose_S();

/**
 * @description: 判断是否为界符
 * @param {type}
 * @return:
 */
bool isDelimiterS_S(char a);

#endif